package gat.application.backgroundUser.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.bitsun.core.common.exception.AppException;
import com.bitsun.core.common.exception.ErrorCode;
import com.bitsun.core.common.persistence.BasePService;
import com.bitsun.core.common.persistence.IPService;
import com.bitsun.core.common.persistence.Pager;
import com.bitsun.core.common.persistence.QueryParamUtils;
import com.google.common.base.CaseFormat;
import gat.application.backgroundUser.BackgroundUserService;
import gat.application.backgroundUser.PermissionsService;
import gat.application.backgroundUser.RolePermissionsService;
import gat.application.backgroundUser.UserRoleService;
import gat.common.util.CurrentThread;
import gat.convertor.backgroundUser.PermissionsReqDtoConvertor;
import gat.convertor.backgroundUser.PermissionsResDtoConvertor;
import gat.dto.req.backgroundUser.PermissionsReqDto;
import gat.dto.req.backgroundUser.UserRoleReqDto;
import gat.dto.res.backgroundUser.BackgroundUserResDto;
import gat.dto.res.backgroundUser.PermissionsResDto;
import gat.infrastructure.persistence.dao.backgroundUser.PermissionsMapper;
import gat.infrastructure.persistence.dao.backgroundUser.RolePermissionsMapper;
import gat.infrastructure.persistence.po.backgroundUser.PermissionsPo;
import gat.infrastructure.persistence.po.backgroundUser.RolePermissionsPo;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.math.NumberUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 示例表，应用（业务编排）层实现
 *
 * @author: tmac
 * @email: tmac
 */
@Slf4j
@Service("permissionsAppService")
@Transactional(rollbackFor = Exception.class)
public class PermissionsServiceImpl implements PermissionsService {

    @Autowired
    private PermissionsReqDtoConvertor permissionsReqDtoConvertor;

    @Autowired
    private PermissionsResDtoConvertor permissionsResDtoConvertor;

    @Autowired
    private UserRoleService userRoleService;

    @Autowired
    private RolePermissionsService rolePermissionsService;

    @Autowired
    private BackgroundUserService backgroundUserService;

    @Autowired
    private RolePermissionsMapper rolePermissionsMapper;

    private IPService<PermissionsPo> permissionsPoService;

    @SuppressWarnings("SpringJavaAutowiringInspection")
    public PermissionsServiceImpl(PermissionsMapper permissionsMapper) {
        this.permissionsPoService = new BasePService(permissionsMapper);
    }


    @Override
    public List<PermissionsResDto> getPermissionsByUserId(UserRoleReqDto reqDto) {
        //为主账户的用户，直接返回所有的权限
        if (ObjectUtil.isNotNull(CurrentThread.getCurrentUser())) {
            reqDto.setUserId(CurrentThread.getCurrentUser().getId());
        }

        BackgroundUserResDto backgroundUserResDto = backgroundUserService.selectOne(reqDto.getUserId());
        if (ObjectUtil.equal(backgroundUserResDto.getUsername(), "admin")) {
            return getIndexPermissionsList();
        }
        //根据用户id查询当前用户所具有的角色
        List<Long> roleIds = userRoleService.selByUserId(reqDto.getUserId());
        //非空判断
        if (CollectionUtil.isEmpty(roleIds)) {
            return null;
        }
        //根据角色id查询当前用户的权限id
        List<Long> bypermissionId = rolePermissionsService.getByRoleId(roleIds);
        if (CollectionUtil.isEmpty(bypermissionId)) {
            return null;
        }
        //id可能具有重复数据，进行去重
        List<Long> permissionIds = bypermissionId.stream().distinct().collect(Collectors.toList());
        List<Long> tempList = new ArrayList<>();
        // 查询父节点 只针对当前两级菜单
        permissionIds.forEach(p -> {
            PermissionsPo permissionsPo = permissionsPoService.getById(p);
            if (ObjectUtil.equals(permissionsPo.getDisplay(), 1)) {
                tempList.add(permissionsPo.getParentId());
            }
        });
        permissionIds.addAll(tempList);

        //查询权限信息
        QueryWrapper<PermissionsPo> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().in(PermissionsPo::getId, permissionIds).orderByAsc(PermissionsPo::getSort);
        queryWrapper.lambda().eq(PermissionsPo::getDisplay, 1);
        List<PermissionsPo> list = permissionsPoService.list(queryWrapper);
        //转换
        List<PermissionsResDto> permissionsResDtos = permissionsResDtoConvertor.poList2DtoList(list);
        return toTree(permissionsResDtos);
    }

    @Override
    public List<PermissionsResDto> getPermissionsList(UserRoleReqDto reqDto) {
        //为主账户的用户，直接返回所有的权限
        if (reqDto.getIsMain()) {
            List<PermissionsPo> list = permissionsPoService.list();
            //转换
            List<PermissionsResDto> permissionsResDtos = permissionsResDtoConvertor.poList2DtoList(list);
            return permissionsResDtos;
        }
        //根据用户id查询当前用户所具有的角色
        List<Long> roleIds = userRoleService.selByUserId(reqDto.getUserId());
        //非空判断
        if (CollectionUtil.isEmpty(roleIds)) {
            return null;
        }
        //根据角色id查询当前用户的权限id
        List<Long> bypermissionId = rolePermissionsService.getByRoleId(roleIds);
        if (CollectionUtil.isEmpty(bypermissionId)) {
            return null;
        }
        //id可能具有重复数据，进行去重
        List<Long> permissionIds = bypermissionId.stream().distinct().collect(Collectors.toList());
        //查询权限信息
        QueryWrapper<PermissionsPo> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().in(PermissionsPo::getId, permissionIds);
        List<PermissionsPo> list = permissionsPoService.list(queryWrapper);

        List<PermissionsPo> userPermissionsList = this.getUserPermissionsList(list, reqDto.getSystem());

        //转换
        List<PermissionsResDto> permissionsResDtos = permissionsResDtoConvertor.poList2DtoList(userPermissionsList);
        return permissionsResDtos;
    }


    @Override
    public PermissionsResDto save(PermissionsReqDto reqDto) {
        PermissionsPo po = permissionsReqDtoConvertor.dto2Po(reqDto);
        /*if (!ObjectUtil.equal(reqDto.getParentId(), 0L)) {
            PermissionsPo permissionsPo = permissionsPoService.getById(reqDto.getParentId());
            if (ObjectUtil.isNotNull(permissionsPo) && !ObjectUtil.equal(permissionsPo.getParentId(), 0L)) {
                throw new AppException("暂仅支持到二级菜单");
            }
        }*/

        if (ObjectUtil.equal(po.getLevel() , 2)) {
            po.setDisplay(0);
        }

        permissionsPoService.save(po);
        PermissionsResDto resDto = permissionsResDtoConvertor.po2Dto(po);
        return resDto;
    }

    @Override
    public boolean deleteByIds(String ids) {
        try {
            List<Long> idLongList =
                    Arrays.asList(ids.split(",")).stream().map(s -> NumberUtils.createLong(s.trim())).collect(Collectors.toList());

            idLongList.forEach(id -> {
                List<RolePermissionsPo> rolePermissionsPos = rolePermissionsMapper.selectList(new LambdaQueryWrapper<RolePermissionsPo>()
                        .eq(RolePermissionsPo::getPermissionId, id)
                );
                if (CollectionUtil.isNotEmpty(rolePermissionsPos)) {
                    throw new AppException("资源下存在关联角色，请勿删除");
                }
            });
            return permissionsPoService.removeByIds(idLongList);
        } catch (Exception e) {
            throw new AppException("参数错误：" + ids, ErrorCode.pc("417"), e);
        }
    }

    @Override
    public Pager<PermissionsResDto> doPager(Map<String, Object> params) {
        Pager<PermissionsPo> poPager = permissionsPoService.queryPage(params, PermissionsPo.class);
        Pager<PermissionsResDto> resDtoPager = permissionsResDtoConvertor.convertPoPager2ResDtoPager(poPager);
        return resDtoPager;
    }

    @Override
    public PermissionsResDto selectOne(Long id) {
        PermissionsPo po = permissionsPoService.getById(id);
        PermissionsResDto resDto = permissionsResDtoConvertor.po2Dto(po);
        return resDto;
    }

    @Override
    public PermissionsResDto selectOne(Map<String, Object> params) {
        QueryWrapper queryWrapper = QueryParamUtils.queryWrapper4eq(PermissionsPo::new, params);
        queryWrapper.last(" limit 1");
        PermissionsPo po = permissionsPoService.getOne(queryWrapper);
        PermissionsResDto resDto = permissionsResDtoConvertor.po2Dto(po);
        return resDto;
    }

    @Override
    public boolean updateProps(Long id, Map<String, Object> params) {
        UpdateWrapper<PermissionsPo> updateWrapper = QueryParamUtils.updateWrapper4Map(PermissionsPo::new, id, params);
        return permissionsPoService.update(new PermissionsPo(), updateWrapper);
    }

    @Override
    public boolean updateProps(Long id, PermissionsReqDto reqDto) {
        PermissionsPo po = permissionsReqDtoConvertor.dto2Po(reqDto);
        po.setId(id);
        return permissionsPoService.updateById(po);
    }


    @Override
    public boolean updateAllProps(Long id, PermissionsReqDto reqDto) {
        UpdateWrapper<PermissionsPo> updateWrapper = Wrappers.update();
        updateWrapper.eq("id", id);
        Field[] fields = PermissionsReqDto.class.getDeclaredFields();
        Arrays.stream(fields).filter(f -> !Modifier.isStatic(f.getModifiers())).forEach(field -> {
            try {
                PropertyDescriptor propertyDescriptor = new PropertyDescriptor(field.getName(), PermissionsReqDto.class);
                Method getMethod = propertyDescriptor.getReadMethod();
                String fileNameCamel = getMethod.getName().substring(3);
                String fileNameUnderline = CaseFormat.LOWER_CAMEL.to(CaseFormat.LOWER_UNDERSCORE, fileNameCamel);
                updateWrapper.set(fileNameUnderline, getMethod.invoke(reqDto));
            } catch (Exception ex) {
                log.warn("属性不存在get方法：" + field.getName(), ex);
            }
        });
        return permissionsPoService.update(new PermissionsPo(), updateWrapper);
    }

    @Override
    public List<PermissionsResDto> getAllPermissionsList() {
        List<PermissionsPo> list = permissionsPoService.list(new LambdaQueryWrapper<PermissionsPo>()
                .orderByAsc(PermissionsPo::getSort)
        );
        //转换
        List<PermissionsResDto> permissionsResDtos = permissionsResDtoConvertor.poList2DtoList(list);
        return toTree(permissionsResDtos);
    }

    @Override
    public List<PermissionsResDto> getIndexPermissionsList() {
        List<PermissionsPo> list = permissionsPoService.list(new LambdaQueryWrapper<PermissionsPo>()
                .eq(PermissionsPo::getDisplay, 1)
                .orderByAsc(PermissionsPo::getSort)
        );
        //转换
        List<PermissionsResDto> permissionsResDtos = permissionsResDtoConvertor.poList2DtoList(list);
        return toTree(permissionsResDtos);
    }


    /**
     * 将数据转换成树格式
     *
     * @param list
     * @return
     */
    public List<PermissionsResDto> toTree(List<PermissionsResDto> list) {
        Map<Long, PermissionsResDto> map = list.stream().collect(Collectors.toMap(PermissionsResDto::getId, a -> a));
        List<PermissionsResDto> result = new LinkedList<>();
        list.forEach(l -> {
            if (0 == l.getParentId()) {
                result.add(l);
            } else {
                if (CollectionUtil.isEmpty(map.get(l.getParentId()).getChildren())) {
                    List<PermissionsResDto> child = new LinkedList<>();
                    child.add(l);
                    map.get(l.getParentId()).setChildren(child);
                } else {
                    map.get(l.getParentId()).getChildren().add(l);
                }
            }
        });
        return result;
    }




    private List<PermissionsPo> getUserPermissionsList(List<PermissionsPo> permissionsPos,String system){
        // 查询所有权限
        List<PermissionsPo> list = permissionsPoService.list();

        //  获取全部id
        List<Long> ids = list.stream().map(PermissionsPo :: getId).collect(Collectors.toList());
        // 转换为map
        Map<Long, PermissionsPo> collect = list.stream().collect(Collectors.toMap(PermissionsPo::getId, a -> a));

        // 递归向上查询
        recursionPermissions(permissionsPos, collect,ids);

        // 去重
        List<PermissionsPo> newList = permissionsPos.stream().collect(Collectors
                .collectingAndThen(
                        Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(PermissionsPo::getId))),
                        ArrayList::new));
        return newList;
    }

    private void recursionPermissions(List<PermissionsPo> permissionsPos, Map<Long, PermissionsPo> collect,List<Long> ids) {



        // 校验结果返回
        List<Long> poIds = permissionsPos.stream().map(PermissionsPo :: getParentId).collect(Collectors.toList());
        List<Long> result = new ArrayList<>();
        result.addAll(ids);
        result.retainAll(poIds);

        ArrayList<PermissionsPo> pos = new ArrayList<>();
        pos.addAll(permissionsPos);

        if(CollectionUtil.isNotEmpty(result)){
            // 向上递归查询当前权限的所有父级权限
            pos.forEach(l->{
                if (ObjectUtil.isNotEmpty(l.getParentId())){
                    permissionsPos.add(collect.get(l.getParentId()));
                }
            });

            // 去除空值
            permissionsPos.removeAll(Collections.singleton(null));

            //  去除已经赋值的元素
            HashSet idSet = new HashSet(ids);
            List<Long> poList = permissionsPos.stream().map(a->a.getId()).collect(Collectors.toList());
            HashSet poIdSet = new HashSet(poList);
            idSet.removeAll(poIdSet);
            List<Long> idList = new ArrayList<>();
            idList.addAll(idSet);

            recursionPermissions(permissionsPos,collect,idList);
        }


    }


}